require "compile.inject_code"
require "compile.wave"
require "compile.template"
require "compile.cjass"
require "compile.jasshelper"
require "compile.native"
require "mpq_util"

local lniloader = require 'fix-wtg.lniloader'

-- 确定应当把地图保存为适合老版本（< 1.24）还是新版本（>= 1.24）的
-- 对于保存为双份，按照当前魔兽版本处理
-- save_type - 保存类型，0到3的取值，意义同设置程序，从上到下依次为0到3
-- runtime_version - 魔兽版本
-- 返回值: 数，如果保存的目标版本和当前版本一致，返回当前版本，否则视情况返回1.20或者1.24（和当前版本不同）
local function determine_map_version(save_type, runtime_version)
    -- 固定旧版本
    if save_type == 1 then
        return runtime_version:is_new() and runtime_version:old() or runtime_version
        -- 固定新版本
    elseif save_type == 2 then
        return runtime_version:is_new() and runtime_version or runtime_version:new()
    else
        -- 按照当前版本或者双份
        return runtime_version
    end
end

-- 编译地图
-- map_path - 地图路径，string或者fs.path
-- option - 编译选项，table类型，支持的选项：
--	enable_preprocessor - 启用wave预处理器，true/false
-- 	enable_jasshelper - 启用JassHelper，true/false
--	enable_jasshelper_debug - 启用JassHelper的Debug，true/false
--	enable_jasshelper_optimization - 启用优化，true/false
--	enable_cjass - 启用cJass编译器，true/false
--	script_injection - 代码注入选项，整数，0表示智能注入，1表示不注入
--	runtime_version - 魔兽版本
-- 返回：true表示成功，false表示失败
local function compile_map(map_path, option)
    -- 统一处理fs.path
    if type(map_path) == "string" then map_path = fs.path(map_path) end
    -- 结果
    local result = nil

    log.trace("Save version " .. tostring(option.runtime_version))

    local compile_t = {
        ['option'] = option,
        ['map_path'] = map_path,
    }

    -- 如果JassHelper开启，执行正常编译
    if option.enable_jasshelper then
        we.show_progress(_("KKWE SaveMap"), 0)
        result = mpq_util:update_file(map_path, "war3map.j",
            -- 解压缩地图脚本，处理然后写回
            function(map_handle, in_script_path)
                -- 开始处理
                log.trace("Processing " .. in_script_path:filename():string())

                compile_t.input = in_script_path
                compile_t.output = nil
                compile_t.map_handle = map_handle
                compile_t.inject_file = function(file_path, path_in_archive)
                    log.trace("[stormlib]import file", path_in_archive)
                    return map_handle:add_file(path_in_archive, file_path)
                end

                -- 未启用用cJass
                if not option.enable_cjass then
                    -- 根据注入选项进行处理（由于Lua的closure，此处可以访问“父”函数的局部变量）
                    if option.script_injection == 0 then
                        we.show_progress(_("KKWE SaveMap"), 10, _("Ineject code"))
                        if not inject_code:compile(compile_t) then
                            return nil
                        end
                        compile_t.input = compile_t.output
                    end

                    we.show_progress(_("KKWE SaveMap"), 20, _("Execute Wave"))
                    -- Wave预处理
                    if not wave:compile(compile_t) then
                        return nil
                    end
                    compile_t.input = compile_t.output
                end

                we.show_progress(_("KKWE SaveMap"), 30, _("Generate Template"))
                if not template:compile(compile_t) then
                    return nil
                end

                return compile_t.output
            end
        )

        -- 开始调用编译工具编译
        if result then
            -- 调用cJass
            if option.enable_cjass then
                we.show_progress(_("KKWE SaveMap"), 40, _("Run CJass"))
                result = cjass:compile(map_path, option)
            end

            -- 调用jasshelepr
            if result then
                we.show_progress(_("KKWE SaveMap"), 50, _("Run JassHelper"))
                result = jasshelper:compile(map_path, option)
            end
        end

        we.show_progress(_("KKWE SaveMap"), 60, _("Making Native"))
        native:compile(compile_t)
    else
        we.show_progress(_("KKWE SaveMap"), 50, _("Run JassHelper"))
        -- 只做语法检查
        result = jasshelper:compile(map_path, option)
    end

    return result
end

-- 本函数当保存地图时调用
-- event_data - 事件参数。table类型，包含了以下成员
--	map_path - 保存的地图路径，字符串类型
-- 返回值：0和正数表示保存成功，负数表示保存失败。如果成功编译，一般返回0
function event.EVENT_SAVE_MAP(event_data)
    log.debug("********************* on save start *********************")

    -- 刷新配置数据
    global_config_reload()

    -- 当前保存的地图路径
    local map_path = fs.path(event_data.map_path)
    local temp_path = map_path:parent_path()
    local source_path = temp_path:parent_path() / map_path:filename()

    log.trace("map_path", map_path:string())
    log.trace("temp_path", temp_path:string())
    log.trace("source_path", source_path:string())

    -- -- 如果地图文件带有只读属性，则先询问是否去掉只读属性
    -- -- 128 == 0200 S_IWUSR
    -- if fs.exists(map_path) and 0 == (map_path:permissions() & 128) then
    --     if gui.yesno_message(nil, _("Whether to remove the read-only attribute from \"%s\"?"), map_path:string()) then
    --         log.trace("Remove the read-only attribute.")
    --         map_path:add_permissions(128)
    --     else
    --         log.trace("Don't the remove read-only attribute.")
    --         return -1
    --     end
    -- end

    -- 获取保存类型
    local save_type = tonumber(global_config["MapSave"]["Option"])

    -- 获取保存选项
    local save_option = {
        -- 是否启用JassHelper
        enable_jasshelper = (global_config["ScriptCompiler"]["EnableJassHelper"] ~= "0"),
        -- 是否使用脚本模式编译
        enable_jasshelper_scriptonly = (global_config["ScriptCompiler"]["EnableJassHelperScriptOnly"] == "1"),
        -- 是否是调试模式
        enable_jasshelper_debug = (global_config["ScriptCompiler"]["EnableJassHelperDebug"] == "1"),
        -- 是否优化地图
        enable_jasshelper_optimization = (global_config["ScriptCompiler"]["EnableJassHelperOptimization"] ~= "0"),
        -- 是否启用cJass
        enable_cjass = (global_config["ScriptCompiler"]["EnableCJass"] == "1"),
        -- 目标魔兽版本
        runtime_version = determine_map_version(save_type, war3_version),
        -- 代码注入选项
        script_injection = tonumber(global_config["ScriptInjection"]["Option"]),
        -- 是否启用YDTrigger
        enable_yd_trigger = plugin.loaders['YDTrigger'] ~= nil,
        -- pjass的版本
        pjass = global_config["PJass"]["Option"],
    }

    -- cjass和脚本注入不能共存
    if save_option.enable_cjass then
        save_option.script_injection = false
    end

    -- 如果保存双份，需要预先拷贝
    local map_path_aux = nil
    if save_type == 3 then
        -- 决定第二份的路径
        if save_option.runtime_version:is_new() then
            map_path_aux = fs.aux_filename(map_path, "hashtable")
        else
            map_path_aux = fs.aux_filename(map_path, "returnbug")
        end

        log.trace("Making copy of the original map.")

        -- true代表覆盖现有文件。false不会覆盖
        pcall(fs.copy_file, map_path, map_path_aux, true)
    end

    -- 编译地图
    local result = compile_map(map_path, save_option)

    -- 如果有第二份，此时处理第二份
    if map_path_aux then
        log.trace("Processing second map")
        save_option.runtime_version = save_option.runtime_version:is_new() and save_option.runtime_version:old() or
            save_option.runtime_version:new()
        compile_map(map_path_aux, save_option)
    end

    if result then
        we.show_progress(_("KKWE SaveMap"), 95, _("Packing"))
        lniloader.pack(map_path)
    end

    we.show_progress(_("KKWE SaveMap"), 100, _("finished"))
    log.debug("Result " .. tostring(result))
    log.debug("********************* on save end *********************")

    if result then return 0 else return -1 end
end

-- 本函数当保存地图时调用
-- event_data - 事件参数。table类型，包含了以下成员
--	map_path - 保存的地图路径，字符串类型
function event.EVENT_PRE_SAVE_MAP(event_data)
    log.debug("********************* on pre_save start *********************")
    local map_path = fs.path(event_data.map_path)
    log.trace("Saving " .. map_path:string())

    -- 如果地图文件带有只读属性，则先询问是否去掉只读属性
    -- 128 == 0200 S_IWUSR
    if fs.exists(map_path) and 0 == (map_path:permissions() & 128) then
        if gui.yesno_message(nil, _("Whether to remove the read-only attribute from \"%s\"?"), map_path:string()) then
            log.trace("Remove the read-only attribute.")
            map_path:add_permissions(128)
        else
            log.trace("Don't the remove read-only attribute.")
        end
    end

    log.debug("********************* on pre_save end *********************")
    return 0
end
